package cn.uncode.dal.generator.support;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import cn.uncode.dal.generator.engine.ConstVal;
import cn.uncode.dal.generator.engine.StringUtils;
import cn.uncode.dal.generator.engine.cfg.GlobalConfig;
import cn.uncode.dal.generator.engine.cfg.ITypeConvert;
import cn.uncode.dal.generator.engine.cfg.MySqlTypeConvert;
import cn.uncode.dal.generator.engine.cfg.StrategyConfig;
import cn.uncode.dal.generator.engine.cfg.TableField;
import cn.uncode.dal.generator.engine.cfg.TableFill;
import cn.uncode.dal.generator.engine.cfg.TableInfo;
import cn.uncode.dal.generator.engine.cfg.rules.NamingStrategy;

public class DbUtil {
	public Statement st;
	
	private ITypeConvert typeConvert = new MySqlTypeConvert();

	public DbUtil() {

	}

	/**
	 * paraMap参数 driverClassName 驱动 JdbcURL jdbc 该字符串为： config.ini 的JdbcURL+IP地址(含端口号)+dbStr+数据库名称 userName 数据库名称 userpwd 数据库密码
	 */
	public Statement getStatement(Map<String, String> paraMap) {
		// 加载数据库驱动
		try {
			Class.forName(paraMap.get("driver"));
			//Connection conn = DriverManager.getConnection(paraMap.get("jdbc"), paraMap.get("userName"), paraMap.get("userpwd"));
			Properties info = new Properties();
			info.setProperty("user", paraMap.get("userName"));
			info.setProperty("password", paraMap.get("userpwd"));
			info.setProperty("remarks", "true"); //设置可以获取remarks信息 
			info.setProperty("useInformationSchema", "true");//设置可以获取tables remarks信息
			Connection conn = DriverManager.getConnection(paraMap.get("jdbc"), info);
			if (!conn.isClosed()) {
			} else {
				return null;
			}
			// statement用来执行SQL语句
			Statement statement = conn.createStatement();
			return statement;
			// 要执行的SQL语句
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	// 读取数据库表信息
	public List<String> getTableNames(Map<String, String> dbInfoMap, String dbName) {
		List<String> tableList = new ArrayList<String>(); // 存储表名
		try {
			st = this.getStatement(dbInfoMap);
			if (st == null) {
				return null;
			}
			// 替换数据库名字占位符
			String selTableSql = dbInfoMap.get("showTable").toString().replace("%", dbName);
			ResultSet tabRs = st.executeQuery(selTableSql);
			// 保存表名
			while (tabRs.next()) {
				tableList.add(tabRs.getString(1));
			}
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
		return tableList;
	}
	
    /**
     * 获取所有的数据库表信息
     */
    private List<TableInfo> getTablesInfo(Map<String, String> dbInfoMap, String dbName, StrategyConfig config, GlobalConfig globalConfig) {
        //所有的表信息
        List<TableInfo> tableList = new ArrayList<>();
        
        try {
			st = this.getStatement(dbInfoMap);
			if (st == null) {
				return null;
			}
			// 替换数据库名字占位符
			String selTableSql = dbInfoMap.get("showTable").toString().replace("%", dbName);
			ResultSet tabRs = st.executeQuery(selTableSql);
			TableInfo tableInfo;
			// 保存表名
			while (tabRs.next()) {
				String tableName = tabRs.getString(1);
				if (StringUtils.isNotEmpty(tableName)) {
                    tableInfo = new TableInfo();
                    tableInfo.setName(tableName);
//                  tableInfo.setComment(tableComment);
                    tableList.add(tableInfo);
                } else {
                    System.err.println("当前数据库为空！！！");
                }
			}
            // 性能优化，只处理需执行表字段 github issues/219
			tableList.forEach(ti -> convertTableFields(dbInfoMap, ti, config.getColumnNaming(), config, globalConfig));
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
        return processTable(tableList, config.getNaming(), config, globalConfig);
    }
    
    
    /**
     * 将字段信息与表信息关联
     *
     * @param tableInfo 表信息
     * @param strategy  命名策略
     * @return ignore
     */
    private TableInfo convertTableFields(Map<String, String> dbInfoMap, TableInfo tableInfo, NamingStrategy strategy, StrategyConfig config, GlobalConfig globalConfig) {
        List<TableField> fieldList = new ArrayList<>();
        String tableName = tableInfo.getName();
        try {
			st = this.getStatement(dbInfoMap);
			if (st == null) {
				return null;
			}
			// 替换表名占位符
			String selColumnSql = dbInfoMap.get("showColumns").toString().replace("%", tableName);
			ResultSet columnRs = st.executeQuery(selColumnSql);
			while (columnRs.next()) {
				TableField field = new TableField();
                String columnName = columnRs.getString(1);
                // 处理其它信息
                field.setName(columnName);
                field.setType(columnRs.getString(2));
                field.setPropertyName(config, processName(field.getName(), strategy, config));
                field.setColumnType(typeConvert.processTypeConvert(globalConfig, field.getType()));
                field.setComment(columnRs.getString("comment"));
                // 填充逻辑判断
                List<TableFill> tableFillList = config.getTableFillList();
                if (null != tableFillList) {
                    // 忽略大写字段问题
                    tableFillList.stream().filter(tf -> tf.getFieldName().equalsIgnoreCase(field.getName()))
                        .findFirst().ifPresent(tf -> field.setFill(tf.getFieldFill().name()));
                }
                fieldList.add(field);
				
				
			}
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
        tableInfo.setFields(fieldList);
        return tableInfo;
    }
    
    
    /**
     * 处理字段名称
     *
     * @return 根据策略返回处理后的名称
     */
    private String processName(String name, NamingStrategy strategy, StrategyConfig config) {
        return processName(name, strategy, config.getFieldPrefix());
    }


    /**
     * 处理表/字段名称
     *
     * @param name ignore
     * @param strategy ignore
     * @param prefix ignore
     * @return 根据策略返回处理后的名称
     */
    private String processName(String name, NamingStrategy strategy, String[] prefix) {
        boolean removePrefix = false;
        if (prefix != null && prefix.length != 0) {
            removePrefix = true;
        }
        String propertyName;
        if (removePrefix) {
            if (strategy == NamingStrategy.underline_to_camel) {
                // 删除前缀、下划线转驼峰
                propertyName = NamingStrategy.removePrefixAndCamel(name, prefix);
            } else {
                // 删除前缀
                propertyName = NamingStrategy.removePrefix(name, prefix);
            }
        } else if (strategy == NamingStrategy.underline_to_camel) {
            // 下划线转驼峰
            propertyName = NamingStrategy.underlineToCamel(name);
        } else {
            // 不处理
            propertyName = name;
        }
        return propertyName;
    }
    
    /**
     * 处理表对应的类名称
     *
     * @param tableList 表名称
     * @param strategy  命名策略
     * @param config    策略配置项
     * @return 补充完整信息后的表
     */
    private List<TableInfo> processTable(List<TableInfo> tableList, NamingStrategy strategy, StrategyConfig config, GlobalConfig globalConfig) {
        String[] tablePrefix = config.getTablePrefix();
        for (TableInfo tableInfo : tableList) {
            String entityName = NamingStrategy.capitalFirst(processName(tableInfo.getName(), strategy, tablePrefix));
            if (StringUtils.isNotEmpty(globalConfig.getEntityName())) {
                tableInfo.setConvert(true);
                tableInfo.setEntityName(String.format(globalConfig.getEntityName(), entityName));
            } else {
                tableInfo.setEntityName(config, entityName);
            }
            if (StringUtils.isNotEmpty(globalConfig.getServiceName())) {
                tableInfo.setServiceName(String.format(globalConfig.getServiceName(), entityName));
            } else {
                tableInfo.setServiceName("I" + entityName + ConstVal.SERVICE);
            }
            if (StringUtils.isNotEmpty(globalConfig.getServiceImplName())) {
                tableInfo.setServiceImplName(String.format(globalConfig.getServiceImplName(), entityName));
            } else {
                tableInfo.setServiceImplName(entityName + ConstVal.SERVICE_IMPL);
            }
            if (StringUtils.isNotEmpty(globalConfig.getControllerName())) {
                tableInfo.setControllerName(String.format(globalConfig.getControllerName(), entityName));
            } else {
                tableInfo.setControllerName(entityName + ConstVal.CONTROLLER);
            }
            // 检测导入包
            checkImportPackages(tableInfo, config);
        }
        return tableList;
    }
    
    
    /**
     * 检测导入包
     *
     * @param tableInfo ignore
     */
    private void checkImportPackages(TableInfo tableInfo, StrategyConfig config) {
        if (StringUtils.isNotEmpty(config.getSuperEntityClass())) {
            // 自定义父类
            tableInfo.getImportPackages().add(config.getSuperEntityClass());
        } 
    }
    

	// 读取表字段信息
	public List<Map<String, String>> getColumnNames(Map<String, String> dbInfoMap, String tabName) {
		List<Map<String, String>> colList = new ArrayList<Map<String, String>>(); // 存储字段信息
		try {
			st = this.getStatement(dbInfoMap);
			if (st == null) {
				return null;
			}
			// 替换表名占位符
			String selColumnSql = dbInfoMap.get("showColumns").toString().replace("%", tabName);
			ResultSet columnRs = st.executeQuery(selColumnSql);
			while (columnRs.next()) {
				Map<String, String> colMap = new HashMap<String, String>();
				colMap.put("filed", columnRs.getString(1));
				colMap.put("type", columnRs.getString(2));
				if (columnRs.getString("comment") != null) {
					colMap.put("remarks", columnRs.getString("comment"));
				}
				colList.add(colMap);
			}
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
		return colList;
	}

	// 读取配置
	@SuppressWarnings("finally")
	public Map<String, HashMap<String, String>> getDbConfigMap() {
		Map<String, HashMap<String, String>> sectionsMap = new HashMap<String, HashMap<String, String>>();
		HashMap<String, String> itemsMap = new HashMap<String, String>();
		String currentSection = "";
		BufferedReader reader = null;
		try {
			// 读取当前文件路径下的ini文件
			System.out.println(this.getClass().getResourceAsStream("config.ini"));
			InputStream configStream = this.getClass().getResourceAsStream("config.ini");
			reader = new BufferedReader(new InputStreamReader(configStream, "UTF-8"));

			String line = null;
			while ((line = reader.readLine()) != null) {
				line = line.trim();
				if ("".equals(line)) {
                    continue;
                }
				if (line.startsWith("[") && line.endsWith("]")) {
					itemsMap = new HashMap<String, String>();
					currentSection = line.substring(1, line.length() - 1);
					sectionsMap.put(currentSection, itemsMap);
					currentSection = "";
				} else {
					int index = line.indexOf("=");
					if (index != -1) {
						String key = line.substring(0, index);
						String value = line.substring(index + 1, line.length());
						itemsMap.put(key, value.trim());
					}
				}
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			return sectionsMap;
		}
	}
}
